package com.lill.system.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.connection.RedisPassword;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.util.StringUtils;

import java.time.Duration;

@Configuration
public class CommonRedisConfig {
    
    @SuppressWarnings("rawtypes")
	@Primary
	@Bean(name="defaultLettuceConnectionFactory")
    public LettuceConnectionFactory defaultLettuceConnectionFactory() {
    	GenericObjectPoolConfig config = new GenericObjectPoolConfig();
        config.setMaxTotal(maxActive);
        config.setMaxIdle(maxIdle);
        config.setMinIdle(minIdle);
        config.setMaxWaitMillis(maxWait);
        config.setTestOnBorrow(testOnBorrow);
        config.setTestOnReturn(testOnReturn);
        config.setTestWhileIdle(testWhileIdle);
    	
        RedisStandaloneConfiguration standaloneConfig = new RedisStandaloneConfiguration();
        standaloneConfig.setHostName(host);
        if (!StringUtils.isEmpty(this.password)) {
        	standaloneConfig.setPassword(RedisPassword.of(this.password));
		} else {
			standaloneConfig.setPassword(RedisPassword.none());
		}
        standaloneConfig.setPort(port);
        standaloneConfig.setDatabase(database);
    	
        LettuceClientConfiguration clientConfig =LettucePoolingClientConfiguration.builder()
        		.commandTimeout(Duration.ofDays(1)).poolConfig(config).build();
    	
         return new LettuceConnectionFactory(standaloneConfig, clientConfig);
    }

    @Bean(name="commonRedisTemplate")
    public RedisTemplate<String, Object> commonRedisTemplate(@Qualifier("defaultLettuceConnectionFactory")LettuceConnectionFactory factory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(factory);
        
        Jackson2JsonRedisSerializer<Object> Jsonserializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
		ObjectMapper om = new ObjectMapper();
		om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
		om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
		Jsonserializer.setObjectMapper(om);
//        redisTemplate.setValueSerializer(Jsonserializer);
//        redisTemplate.setHashValueSerializer(Jsonserializer);

		RedisSerializer<String> stringSerializer = new StringRedisSerializer();
		redisTemplate.setKeySerializer(stringSerializer);
		redisTemplate.setHashKeySerializer(stringSerializer);
                
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

    @Value("${common.host}")
    private String host;
    @Value("${common.port}")
    private Integer port;
    @Value("${common.password}")
    private String password;
    @Value("${common.database}")
    private Integer database;

    @Value("${common.lettuce.pool.maxActive}")
    private Integer maxActive;
    @Value("${common.lettuce.pool.maxIdle}")
    private Integer maxIdle;
    @Value("${common.lettuce.pool.maxWait}")
    private Long maxWait;
    @Value("${common.lettuce.pool.minIdle}")
    private Integer minIdle;
    @Value("${common.lettuce.pool.testOnBorrow}")
    private boolean testOnBorrow;
    @Value("${common.lettuce.pool.testOnReturn}")
    private boolean testOnReturn;
    @Value("${common.lettuce.pool.testWhileIdle}")
    private boolean testWhileIdle;
}
